package com.mrdeer.iot.utils;

import cn.hutool.core.util.HexUtil;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;

/**
 * @Author: xie jianchu
 */
@Slf4j
public class HexHelper {
    /**
     * 数字转16进制字符串
     *
     * @param input
     * @return
     */
    public static String number2HexStr(String input) {
        String output = "";
        if (input.length() % 2 != 0) {
            input += "0";
        }
        int count = input.length() / 2;
        for (int i = 0; i < count; i++) {
            String sub = input.substring(i * 2, i * 2 + 2);
            int num = getIntSafely(sub);
            output += int2Hex(num);
        }
        return output;
    }

    /**
     * 16进制字符串转数字
     *
     * @param input
     * @return
     */
    public static String hexStr2number(String input) {
        String output = "";
        if (input.length() % 2 != 0) {
            input += "0";
        }
        int count = input.length() / 2;
        for (int i = 0; i < count; i++) {
            String sub = input.substring(i * 2, i * 2 + 2);
            int temp = hexChar2int(sub.substring(0, 1)) * 16 + hexChar2int(sub.substring(1, 2));
            if (temp < 10) {
                output += "0" + temp;
            } else {
                output += temp + "";
            }
        }
        return output;
    }

    /**
     * 16进制字符串转10进制
     *
     * @param input
     * @return
     */
    public static int hexStr2Int(String input) {
        int output = 0;
        int count = input.length();
        for (int i = 0; i < count; i++) {
            String sub = input.substring(i, i + 1);
            int temp = (int) (hexChar2int(sub) * Math.pow(16, count - 1 - i));
            output += temp;
        }
        return output;
    }

    /**
     * 16进制字符串转10进制
     *
     * @param input
     * @return
     */
    public static long hexStr2Long(String input) {
        long output = 0;
        int count = input.length();
        for (int i = 0; i < count; i++) {
            String sub = input.substring(i, i + 1);
            long temp = (long) (hexChar2int(sub) * Math.pow(16, count - 1 - i));
            output += temp;
        }
        return output;
    }

    /**
     * 安全的获取整数
     *
     * @param str
     * @return
     */
    public static int getIntSafely(String str) {
        int result = 0;
        try {
            result = Integer.parseInt(str);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 10进制转16进制
     *
     * @param input
     * @return
     */
    public static String int2Hex(int input) {
        String result = "";
        if (input < 16) {
            result = "0" + intChar2Hex(input);
        } else {
            result = intChar2Hex(input / 16) + intChar2Hex(input % 16);
        }
        return result;
    }

    /**
     * 整数转16进制
     *
     * @param input
     * @return
     */
    public static String intChar2Hex(int input) {
        String result = "0";
        if (input < 10) {
            result = "" + input;
        } else {
            switch (input) {
                case 10:
                    result = "A";
                    break;
                case 11:
                    result = "B";
                    break;
                case 12:
                    result = "C";
                    break;
                case 13:
                    result = "D";
                    break;
                case 14:
                    result = "E";
                    break;
                case 15:
                    result = "F";
                    break;
            }
        }
        return result;
    }

    public static final String bytesToHexString(byte[] bArray) {
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2) {
                sb.append(0);
            }
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 16进制字符转整数
     *
     * @param input
     * @return
     */
    public static int hexChar2int(String input) {
        int result = 0;
        try {
            result = Integer.parseInt(input);
        } catch (Exception e) {
            if (input.equalsIgnoreCase("A")) {
                result = 10;
            } else if (input.equalsIgnoreCase("B")) {
                result = 11;
            } else if (input.equalsIgnoreCase("C")) {
                result = 12;
            } else if (input.equalsIgnoreCase("D")) {
                result = 13;
            } else if (input.equalsIgnoreCase("E")) {
                result = 14;
            } else if (input.equalsIgnoreCase("F")) {
                result = 15;
            }
        }
        return result;
    }

    //使用1字节就可以表示b
    public static String numToHex8(int b) {
        return String.format("%02x", b);//2表示需要两个16进行数
    }

    //需要使用2字节表示b
    public static String numToHex16(int b) {
        return String.format("%04x", b);
    }

    //需要使用4字节表示b
    public static String numToHex32(int b) {
        return String.format("%08x", b);
    }


    /**
     * 获取高四位
     *
     * @param data
     * @return
     */
    public static int getHeight4(byte data) {
        int height;
        height = ((data & 0xf0) >> 4);
        return height;
    }

    /**
     * 获取低四位
     *
     * @param data
     * @return
     */
    public static int getLow4(byte data) {
        int low;
        low = (data & 0x0f);
        return low;
    }

    /**
     * c-byte数组转换成java-int值 <br/> 高位在前 <br/> [24 - 16 - 08 - 00]
     *
     * @param buffer byte数组
     * @param index  转换开始位置
     * @param len    转换的长度
     */
    public static int cbyte2intHigh(byte[] buffer, int index, int len) {
        if (buffer == null || index + len > buffer.length) {
            return 0;
        }
        int value = 0;
        for (int i = 0, j = len - 1; i < len; i++, j--) {
            value += (cbyte2Int(buffer[i + index]) << (j * 8));
        }
        return value;
    }


    /**
     * c无符号的值，转换成java-int值
     */
    public static int cbyte2Int(byte byteNum) {
        return byteNum & 0xff;
    }

    public static byte[] byteMerger(byte[] bt1, byte[] bt2) {
        byte[] bt3 = new byte[bt1.length + bt2.length];
        System.arraycopy(bt1, 0, bt3, 0, bt1.length);
        System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
        return bt3;
    }

    /**
     * 十六进制转换字符串
     *
     * @return String 对应的字符串
     */
    public static String hexStr2Str(String hexStr) {
        String str = "0123456789ABCDEF";
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int n;

        for (int i = 0; i < bytes.length; i++) {
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xff);
        }
        return new String(bytes);
    }

    /**
     * 字节数组转版本号
     */
    public static String hexStr2Version(String input) {
        int[] ints = new int[4];
        String output = "";
        if (input.length() % 2 != 0) {
            input += "0";
        }
        int count = input.length() / 2;
        for (int i = 0; i < count; i++) {
            String sub = input.substring(i * 2, i * 2 + 2);
            int temp = hexChar2int(sub.substring(0, 1)) * 16 + hexChar2int(sub.substring(1, 2));
            ints[i] = temp;
        }
        return String.format("%d.%d.%d.%d", ints[0], ints[1], ints[2], ints[3]);
    }


    public static String hexXOR(String hex1, String hex2) {
        BigInteger i1 = new BigInteger(hex1, 16);
        BigInteger i2 = new BigInteger(hex2, 16);
        BigInteger res = i1.xor(i2);
        return res.toString(16).toUpperCase();
    }


    // 加密
    public static byte[] Encrypt(String sSrc, String sKey) throws Exception {
        if (sKey == null) {
            System.out.print("Key为空null");
            return null;
        }
        // 判断Key是否为16位
        if (sKey.length() != 16) {
            System.out.print("Key长度不是16位");
            return null;
        }
        byte[] raw = sKey.getBytes("utf-8");
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));

        return encrypted;
    }

    // 加密
    public static byte[] Encrypt(byte[] sSrc, byte[] aesEncrypt) throws Exception {
        if (aesEncrypt == null) {
            System.out.print("Key为空null");
            return null;
        }
        // 判断Key是否为16位
       /* if (sKey.length() != 16) {
            System.out.print("Key长度不是16位");
            return null;
        }*/
        byte[] raw = aesEncrypt;
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(sSrc);

        return encrypted;
    }


    /**
     * 基于Sn的异或加密
     */
    public static String getXOR_DATA(String ly2Package, String deviceSn) {
        int ly2packLength = ly2Package.length();
        //得到sn前四位
        String getStart4 = deviceSn.substring(0, 4);
        //得到sn后16位
        String getLast16 = deviceSn.substring(4, deviceSn.length());

        String last16Hex = HexUtil.encodeHexStr(getLast16.getBytes());

        String result1 = XOR(ly2Package, ly2packLength, last16Hex);
        if (result1 != null) {
            return result1;
        }
        return "";

    }


    public static String XOR(String content, int cotentLength, String keyHex) {
        int keyHexLength = keyHex.length();

        String result = keyHex;

        if (keyHexLength > cotentLength) {
            result = keyHex.substring(0, cotentLength);
        } else {
            int add = cotentLength - keyHexLength;


            int count = add / keyHexLength;
            int remainder = add % keyHexLength;//余数


            for (int i = 0; i < count; i++) {
                result = result + keyHex;
            }

            if (remainder != 0) {
                result = result + keyHex.substring(0, remainder);
            }

        }

        if (result.length() == cotentLength) {
            //进行异或
            String hexXOR = HexHelper.hexXOR(result, content);
            if (hexXOR.length() != cotentLength) {
                int absCount = Math.abs(cotentLength - hexXOR.length());
                for (int i = 0; i < absCount; i++) {
                    hexXOR = "0" + hexXOR;
                }
                return hexXOR;
            }
            return hexXOR;
        }
        return null;
    }

    public static String timeStr2Hex(String time) {
        String result = "";
        int length = time.length() / 2;
        int j = 0;
        for (int i = 0; i < length; i++) {
            String oneStr = numToHex8(Integer.parseInt(time.substring(j, j + 2)));
            j += 2;
            if (oneStr.length() == 1) {
                oneStr = "0" + oneStr;
            }
            result = result + oneStr;
        }
        return result;
    }

    public static String hexToBin(String hex) {
        String bin = "";
        String binFragment = "";
        int iHex;
        hex = hex.trim();
        hex = hex.replaceFirst("0x", "");

        for (int i = 0; i < hex.length(); i++) {
            iHex = Integer.parseInt("" + hex.charAt(i), 16);
            binFragment = Integer.toBinaryString(iHex);

            while (binFragment.length() < 4) {
                binFragment = "0" + binFragment;
            }
            bin += binFragment;
        }
        return bin;
    }

    /**
     * 字节数组转16进制数
     *
     * @param bytes 字节数组
     * @return 返回值
     */
    public static String convertBytesToHexString(byte[] bytes) {
        StringBuilder res = new StringBuilder("");
        for (byte aByte : bytes) {
            String temp = Integer.toHexString(aByte & 0xff);
            if (temp.length() == 1) {
                temp = '0' + temp;
            }
            res.append(temp);
        }
        return res.toString().toUpperCase();
    }

    /**
     * 功能：将字节数组转成二进制
     *
     * @param bytes
     * @return
     */
    public static String convertBytesToBin(byte[] bytes) {
        return hexToBin(convertBytesToHexString(bytes));
    }

    /**
     * 功能：将整数转化为合法的十六进制字符串
     *
     * @param source 整数
     * @param len    至少占多少个字节
     * @return 十六进制数
     * <p>
     * 说明：为什么要有len？
     * 某些场景需要指定大小的二进制字符串（这里的大小指的是转化为字节数组后所占大小）
     * 例如，现在需要把1这个整数转化为十六进制数，
     * 如果len为1，结果为 01
     * 如果len为2，结果为 0001
     * <p>
     * 但是len不限制大小，比如len设置为1，source为125120，那么结果仍然为1e8c0，
     * 不会截断结果
     */
    public static String convertIntToHexString(int source, int len) {
        //一个字节占两位，所以要乘以2
        len <<= 1;
        StringBuilder res = new StringBuilder(Integer.toHexString(source));
        int comp = len - res.length();

        //位数不足，需要补0
        if (comp > 0) {
            for (int i = 0; i < comp; i++) {
                res.insert(0, "0");
            }
        }

        return res.toString();
    }
}
